package hai.com.android_test.utils;

import android.content.Context;
import android.util.Log;

import org.apache.http.HttpStatus;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.CookieHandler;
import java.net.CookieManager;
import java.net.HttpCookie;
import java.net.HttpURLConnection;
import java.net.URISyntaxException;
import java.net.URL;
import java.security.KeyStore;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;

/**
 * Created by 黄海 on 2016/10/8.
 */
public class HttpUtils {
    private static final String BOUNDARY = "------WebKitFormBoundaryXt9bHBmce2A1Qt0j";
    private static final int CONNECTION_TIMEOUT = 7 * 1000;
    private static final int SOCKET_TIMEOUT = 7 * 1000;
    private static SSLSocketFactory sslSocketFactory;
    private static CookieManager cookieManager;
    private static final String COOKIES_HEADER = "Set-Cookie";
    private static Map<String, String> requestHeader = new HashMap<>();

    public static void init(Context context) {
        CookieHandler.setDefault(new CookieManager());//如果这里设置了，就不需要手动管理cookie了

        KeyStore keyStore = null;
        InputStream is = null;
        CertificateFactory cf = null;

        try {
            cf = CertificateFactory.getInstance("X.509");
            is = context.getResources().getAssets().open("cer_test.crt");
            Certificate ca = cf.generateCertificate(is);
            Logger.e("证书信息：" + ((X509Certificate) ca).getSubjectDN());

            // Create a KeyStore containing our trusted CAs
            keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            keyStore.load(null, null);
            keyStore.setCertificateEntry("ca", ca);

            // Create a TrustManager that trusts the CAs in our KeyStore
            String defaultAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
            TrustManagerFactory tmf = TrustManagerFactory.getInstance(defaultAlgorithm);
            tmf.init(keyStore);

            // Create an SSLContext that uses our TrustManager
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, tmf.getTrustManagers(), null);//信任证书密钥
//            sslContext.init(null, new TrustManager[]{new UnSafeTrustManager()}, null);//信任所有
            sslSocketFactory = sslContext.getSocketFactory();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static String get(String uri) {
        try {
            byte[] bytes = performRequest(new URL(uri), null, null, Method.GET);
            if (bytes != null && bytes.length > 0) {
                String result = new String(bytes);
                Logger.e("响应结果:" + result);
                return result;
            } else {
                Logger.e("请求出错:请检查好网络设置");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static String post(String url, Map<String, File> files) {
        try {
            byte[] bytes = performRequest(new URL(url), null, files, Method.POST);
            if (bytes != null && bytes.length > 0) {
                String result = new String(bytes);
                Logger.e("响应结果:" + result);
                return result;
            } else {
                Logger.e("请求出错:请检查好网络设置");
            }
        } catch (Exception e) {
            Logger.e("请求出错:请检查好网络设置");
            e.printStackTrace();
        }
        return null;
    }

    private static byte[] performRequest(URL url, byte[] params, Map<String, File> files, int method) throws Exception {
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.setConnectTimeout(CONNECTION_TIMEOUT);
        connection.setReadTimeout(SOCKET_TIMEOUT);
        connection.setUseCaches(false);
        connection.setDoInput(true);
        if ("https".equals(url.getProtocol()) && sslSocketFactory != null) {
            ((HttpsURLConnection) connection).setSSLSocketFactory(sslSocketFactory);
            ((HttpsURLConnection) connection).setHostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    Log.e("hhp", "verify: " + hostname + "|" + session.getPeerHost());
                    return hostname.equals(session.getPeerHost());
                }
            });
        }
        //设置请求头
        for (String headerName : getRequestHeader().keySet()) {
            connection.addRequestProperty(headerName, getRequestHeader().get(headerName));
        }
        //设置cookie
//        if (cookieManager.getCookieStore().getCookies().size() > 0) {
//            connection.setRequestProperty("Cookie",
//                    TextUtils.join(";", cookieManager.getCookieStore().getCookies()));
//            Logger.i("Cookie=" + connection.getRequestProperty("Cookie"));
//        }
        setConnectionParametersForRequest(connection, params, method);
//        setConnectionParametersForRequest(connection, files);

        int responseCode = connection.getResponseCode();
        if (responseCode != 200) {
            Logger.e("请求出错:responseCode=" + responseCode);
            throw new IOException("Could not retrieve response code from HttpUrlConnection.");
        }
        if (hasResponseBody(method, responseCode)) {
//            readResponseCookies(url, connection);
            InputStream inputStream;
            try {
                inputStream = connection.getInputStream();
            } catch (IOException ioe) {
                inputStream = connection.getErrorStream();
            }
            if (inputStream != null) {
                int length = connection.getContentLength();
                byte[] buffer = new byte[length];
                inputStream.read(buffer);
                return buffer;
            }
        }
        return new byte[0];
    }

    /**
     * 设置请求参数
     *
     * @param connection
     * @param postBody
     * @param method
     * @throws IOException
     */
    private static void setConnectionParametersForRequest(HttpURLConnection connection, byte[] postBody, int method) throws IOException {
        switch (method) {
            case Method.POST:
                byte[] body = postBody;
                connection.setRequestMethod("POST");
                if (body != null) {
                    connection.setDoOutput(true);
                    connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
                    DataOutputStream out = new DataOutputStream(connection.getOutputStream());
                    out.write(postBody);
                    out.close();
                }
                break;
            case Method.GET:
                connection.setRequestMethod("GET");
                Logger.e("发送请求(get):" + connection.getURL().toString());
                break;
        }
    }

    /**
     * 上传文件
     *
     * @param connection
     * @param files
     * @throws IOException
     */
    private static void setConnectionParametersForRequest(HttpURLConnection connection, Map<String, File> files) throws IOException {
        String contentType = "application/octet-stream";
//        String contentType="image/jpeg";
        if (files != null && files.size() > 0) {
            connection.setDoOutput(true);
            connection.setRequestMethod("POST");
            connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);
            DataOutputStream out = new DataOutputStream(connection.getOutputStream());
            Iterator<Map.Entry<String, File>> iterator = files.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry<String, File> next = iterator.next();
                String name = next.getKey();
                File value = next.getValue();
                if (value == null)
                    return;
                StringBuilder strBuf = new StringBuilder();
                strBuf.append("\r\n").append("--").append(BOUNDARY).append("\r\n");
                strBuf.append("Content-Disposition: form-data; name=\"" + name + "\"; filename=\"" + value.getName() + "\"\r\n");
                strBuf.append("Content-Type:" + contentType + "\r\n\r\n");
                out.write(strBuf.toString().getBytes());
                DataInputStream dis = new DataInputStream(new FileInputStream(value));
                int bytes = -1;
                byte[] buffer = new byte[1024 * 4];
                while ((bytes = dis.read(buffer)) != -1) {
                    out.write(buffer);
                }
                dis.close();
            }
            byte[] endData = ("\r\n--" + BOUNDARY + "--\r\n").getBytes();
            out.write(endData);
            out.flush();
            out.close();
        }
        Logger.e("发送请求(post):" + connection.getURL().toString());
        if (files != null) {
            for (File file : files.values()) {
                Logger.e("发送文件:" + new String(file.getName()));
            }
        }
    }

    private static Map<String, String> getRequestHeader() {
        requestHeader.put("Connection", "Keep-Alive");
        requestHeader.put("Accept-Encoding", "identity");//高版本避免conn.getContentLength()＝＝－１;
        return requestHeader;
    }

    public interface Method {
        int GET = 1;
        int POST = 2;
        int HEAD = 4;
    }

    /**
     * 存储cookies
     *
     * @param url
     * @param connection
     * @throws URISyntaxException
     */
    private static void readResponseCookies(URL url, HttpURLConnection connection) throws URISyntaxException {
        Map<String, List<String>> headerFields = connection.getHeaderFields();
        final List<String> cookiesHeader = headerFields.get(COOKIES_HEADER);
        if (cookiesHeader != null) {
            for (String cookie : cookiesHeader) {
                cookieManager.getCookieStore().add(url.toURI(), HttpCookie.parse(cookie).get(0));
            }
        }
    }

    private static boolean hasResponseBody(int requestMethod, int responseCode) {
        return requestMethod != Method.HEAD
                && !(HttpStatus.SC_CONTINUE <= responseCode && responseCode < HttpStatus.SC_OK)
                && responseCode != HttpStatus.SC_NO_CONTENT
                && responseCode != HttpStatus.SC_NOT_MODIFIED;
    }
}
